package com.house365.app.analyse;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.util.Log;

import com.house365.app.analyse.dao.AnalyticsDao;
import com.house365.app.analyse.data.AnalyseMetaData;
import com.house365.app.analyse.data.Event;
import com.house365.app.analyse.data.Platform;
import com.house365.app.analyse.ext.json.JSONArray;
import com.house365.app.analyse.ext.json.JSONException;
import com.house365.app.analyse.ext.json.JSONObject;
import com.house365.app.analyse.http.AnalyseHttpAPI;
import com.house365.app.analyse.store.SharedPreferencesUtil;
import com.house365.core.application.BaseApplication;

/**
 * @author py
 * @date 2012-8-13
 * @comment
 * @modified by py 2012-12-6
 */
public class HouseAnalyse {
	private static final String HOUSE_ANALYSE = "HOUSE_ANALYSE";
	private static String deviceId;
	private static String version;
	public static String provider;
	private static String screen;
	private static AnalyseConfig config;
	private static SharedPreferencesUtil pref;
	private static int flushSize = 10;
	private static AnalyseHttpAPI api = new AnalyseHttpAPI();

	public static final int OP_S = 1;
	public static final int OP_E = 0;

	private static Object syn_obj = new Object();
	private static String network;

	private static String digest;
	private static Map<String, String> headers;
    private static AnalyticsDao mAnalyticsDao;

	private synchronized static void init(Context context) {
		if (deviceId == null) {
			// 获取设备信息
			TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
			deviceId = telephonyManager.getDeviceId();
			headers = new HashMap<String, String>();
			digest = ((BaseApplication) context.getApplicationContext()).getDigest();
			headers.put("d", digest);
			// 获取安装包信息
			PackageInfo info;
			try {
				info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
				version = info.versionName;
			} catch (NameNotFoundException e) {
				e.printStackTrace();
			}
			// 获取网络提供商
			String IMSI = telephonyManager.getSubscriberId();
			// IMSI号前面3位460是国家，紧接着后面2位00 02是中国移动，01是中国联通，03是中国电信。
			if (IMSI != null) {
				if (IMSI.startsWith("46000") || IMSI.startsWith("46002")) {
					provider = "中国移动";
				} else if (IMSI.startsWith("46001")) {
					provider = "中国联通";
				} else if (IMSI.startsWith("46003")) {
					provider = "中国电信";
				} else {
					provider = "未知";
				}
			} else {
				provider = "未知";
			}

			ConnectivityManager connectionManager = (ConnectivityManager) context
					.getSystemService(Context.CONNECTIVITY_SERVICE);
			NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
			if (networkInfo != null) {
				network = networkInfo.getTypeName();
			}
			mAnalyticsDao = new AnalyticsDao(context);
		}

	}

	public static String getScreen(Context context) {
		if (screen == null && config != null) {
			DisplayMetrics dm = config.getDispalyMetrics();
			screen = dm.widthPixels + "*" + dm.heightPixels;
		}
		return screen;
	}

	public static void setInitConfig(AnalyseConfig tconfig) {
		config = tconfig;
		flushSize = config.getBufferSize();

	}

	private static long getTimeWithSeconds(Date date) {
		return date.getTime() / 1000;
	}

	// add city parameter!!!!
	public static AnalyseMetaData onEvent(Context context, int event, String eventobj, String page, Date startTime,
			Date endtTme, boolean saveData) {
		// get current version
		if (digest == null) {
			init(context);
		}
		String city = ((BaseApplication) context.getApplicationContext()).getCityName();
		AnalyseMetaData data = new AnalyseMetaData(config.getApp(), version, Platform.PLATFORM_ANDROID, deviceId,
				event, eventobj, getTimeWithSeconds(new Date()), page, provider, getScreen(context), Build.MODEL,
				startTime == null ? -1 : getTimeWithSeconds(startTime), endtTme == null ? -1
						: getTimeWithSeconds(endtTme), config.getChannel(), network, city, Build.VERSION.RELEASE);
		if (saveData) {
			if (mAnalyticsDao == null) {
			    mAnalyticsDao = new AnalyticsDao(context);
            }
			mAnalyticsDao.insert(data);
		}
		return data;
	}

	/**
	 * 重载方法，增加了扩展字段 extra_data，增加ad,click等时间的额外数据
	 * 
	 * @param context
	 * @param event
	 * @param eventobj
	 * @param page
	 * @param startTime
	 * @param endtTme
	 * @param extra_data
	 * @param saveData
	 * @return
	 */
	public static AnalyseMetaData onEvent(Context context, int event, String eventobj, String page, Date startTime,
			Date endtTme, String extra_data, boolean saveData) {
		// get current version
		if (digest == null) {
			init(context);
		}
		String city = ((BaseApplication) context.getApplicationContext()).getCityName();
		AnalyseMetaData data = new AnalyseMetaData(config.getApp(), version, Platform.PLATFORM_ANDROID, deviceId,
				event, eventobj, getTimeWithSeconds(new Date()), page, provider, getScreen(context), Build.MODEL,
				startTime == null ? -1 : getTimeWithSeconds(startTime), endtTme == null ? -1
						: getTimeWithSeconds(endtTme), config.getChannel(), network, city, Build.VERSION.RELEASE,
				extra_data);
		if (saveData) {
		    if (mAnalyticsDao == null) {
                mAnalyticsDao = new AnalyticsDao(context);
            }
            mAnalyticsDao.insert(data);
		}
		return data;
	}

	public static AnalyseMetaData onPageResume(Context context) {
		ActivityInfo actInfo = getActivityInfo((Activity) context);
		String pageName = "";
		if (actInfo != null) {
			CharSequence cs = actInfo.loadLabel(context.getPackageManager());
			pageName = (cs == null ? "" : cs.toString());
		} else {
			pageName = context.getClass().getName();
		}
		return onEvent(context, Event.EVENT_PAGE, pageName, pageName, new Date(), null, false);
	}

	public static AnalyseMetaData onPagePause(AnalyseMetaData data) {
		data.setEndtime(getTimeWithSeconds(new Date()));
//		if (mAnalyticsDao == null) {
//            mAnalyticsDao = new AnalyticsDao(context);
//        }
        mAnalyticsDao.insert(data);
		ayncFlush();
		return data;
	}

	public static AnalyseMetaData onAppStart(Context context) {
		return onEvent(context, Event.EVENT_APP, config.getApp(), null, new Date(), null, false);
	}

	public static AnalyseMetaData onAppDestory(BaseApplication application, AnalyseMetaData data) {
		data.setCity(application.getCityName());
		data.setEndtime(getTimeWithSeconds(new Date()));
		if (mAnalyticsDao == null) {
            mAnalyticsDao = new AnalyticsDao(application);
        }
        mAnalyticsDao.insert(data);
		return data;
	}

	/**
	 * 自定义点击事件
	 * 
	 * @param context
	 * @param eventobj
	 * @param type
	 * @param extra_data
	 * @return
	 */
	public static AnalyseMetaData onViewClick(Context context, String eventobj, String type, String extra_data) {
		ActivityInfo actInfo = getActivityInfo((Activity) context);
		String pageName = "";
		if (actInfo != null) {
			CharSequence cs = actInfo.loadLabel(context.getPackageManager());
			pageName = (cs == null ? "" : cs.toString());
		} else {
			pageName = context.getClass().getName();
		}
		AnalyseMetaData data = onEvent(context, Event.EVENT_ONCLICK, eventobj, pageName, new Date(), new Date(),
				extra_data, true);
		ayncFlush();
		return data;
	}

	/**
	 * 接口请求时调用
	 * 
	 * @param context
	 * @param eventobj
	 * @param type
	 * @return
	 */
	public static AnalyseMetaData onCallAPI(Context context, String eventobj, String type) {
		AnalyseMetaData data = onEvent(context, Event.EVENT_CALL_API, eventobj, type, new Date(), new Date(), true);
		ayncFlush();
		return data;
	}

	/**
	 * 点击广告时调用
	 * 
	 * @param context
	 * @param adname
	 * @param type
	 * @param extra_data
	 * @return
	 */
	public static AnalyseMetaData onAD(Context context, String adname, String type, String extra_data) {
		AnalyseMetaData data = onEvent(context, Event.EVENT_AD, adname, type, new Date(), new Date(), extra_data, true);
		ayncFlush();
		return data;
	}

	/**
	 * 拨打电话时，调用
	 * 
	 * @param context
	 * @param toNo
	 * @param type
	 * @return
	 */
	public static AnalyseMetaData onCall(Context context, String toNo, String type) {
		AnalyseMetaData data = onEvent(context, Event.EVENT_CALL, toNo, type, new Date(), new Date(), true);
		ayncFlush();
		return data;
	}

	/**
	 * 城市切换
	 * 
	 * @param context
	 * @return
	 */
	public static AnalyseMetaData onCity(Context context) {
		ActivityInfo actInfo = getActivityInfo((Activity) context);
		String pageName = "";
		if (actInfo != null) {
			CharSequence cs = actInfo.loadLabel(context.getPackageManager());
			pageName = (cs == null ? "" : cs.toString());
		} else {
			pageName = context.getClass().getName();
		}
		AnalyseMetaData data = onEvent(context, Event.EVENT_CITY, pageName, pageName, new Date(), new Date(), true);
		ayncFlush();
		return data;
	}

	/**
	 * 发送错误日志.
	 */
    public static void onCrash(Context context, Throwable t) {
        StringWriter w = new StringWriter();
        t.printStackTrace(new PrintWriter(w));
        onEvent(context, Event.EVENT_CRASH, w.toString(), "", new Date(), new Date(), true);
        flush();
    }

	public static boolean flush() {
		try {
		    if (mAnalyticsDao == null) {
		        return false;
		    }
			List<AnalyseMetaData> list = mAnalyticsDao.select();
            boolean flag = flushData(list);
			if (flag) {
	            mAnalyticsDao.clear();
			}
			return flag;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	public static boolean isAyncing = false;

	public static boolean getAync() {
		synchronized (syn_obj) {
			return isAyncing;
		}
	}

	public static void setAync() {
		synchronized (syn_obj) {
			isAyncing = !isAyncing;
		}
	}

	public static void ayncFlush() {
		if (getAync() == false) {
			setAync();
			new Thread() {
				@Override
				public void run() {
					List<AnalyseMetaData> datas = null;
					try {
						datas = mAnalyticsDao.select();
					} catch (Exception e) {
						e.printStackTrace();
					}
					if (datas != null && datas.size() >= flushSize) {
						boolean isSuccess = flushData(datas);
						if (isSuccess) {
							// clean data
							for (AnalyseMetaData data : datas) {
							    mAnalyticsDao.delete(data);
							}
						}
					}
					setAync();
				}
			}.start();
		}

	}

	private static boolean flushData(List<AnalyseMetaData> datas) {
		try {
			List<NameValuePair> params = new ArrayList<NameValuePair>();
			params.add(new BasicNameValuePair("service", generateRequestData("analyse", "addAnalyseMetaDataWithList",
					datas).toString()));
			String s = api.post(config.getUrl(), params, headers);
			JSONObject json = new JSONObject(s);
			if (json != null && "success".equals(json.getString("result")) && OP_S == json.getInt("returnobject")) {
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	private static JSONObject generateRequestData(String service, String method, List<AnalyseMetaData> datas)
			throws JSONException {
		JSONObject json = new JSONObject();
		json.put("name", service);
		json.put("method", method);
		JSONArray params = new JSONArray();
		params.put(new JSONArray(datas));
		json.put("params", params);
		Log.i("HouseAnalyse", json.toString());
		return json;
	}

	private static ActivityInfo getActivityInfo(Activity activity) {
		try {
			PackageManager pm = activity.getPackageManager();
			ComponentName componentName = activity.getComponentName();
			return pm.getActivityInfo(componentName, 0);
		} catch (NameNotFoundException e) {
			return null;
		}
	}
}
